package org.zhao.nettydemos.guava;

import com.google.common.util.concurrent.RateLimiter;
import lombok.extern.slf4j.Slf4j;

/**
 * @Auther: xiaohui.zhao
 * @Date: 2021/9/18 13:19
 * @Description:  使用Guava框架实现令牌桶算法
 */
@Slf4j
public class TokenBucketLimiter {

    public static void main(String[] args) {
        // 每秒中生成 5 个令牌
        RateLimiter limiter = RateLimiter.create(5);

        // 返回值表示从令牌桶中获取一个令牌所花费的时间 ， 单位: s
        /**
        System.out.println(limiter.acquire(1));
        System.out.println(limiter.acquire(1));
        System.out.println(limiter.acquire(1));
        System.out.println(limiter.acquire(1));
        System.out.println(limiter.acquire(1));
        System.out.println(limiter.acquire(1));
        System.out.println(limiter.acquire(1));
        System.out.println(limiter.acquire(1));
        System.out.println(limiter.acquire(1));
        System.out.println(limiter.acquire(1));


         * 程序结果解析 ：
         * 创建的时候回向桶中放入一个令牌  ， 当程序第一次获取令牌的时候 就直接有了 ， 所以获取令牌的时间是 0.0秒
         * 之后的获取 大致都在0.2秒左右 也就是符合 1秒5个 ， 0.2秒一个的规则限制
         */

        // 以下模拟突发流量
        System.out.println(limiter.acquire(50));
        System.out.println(limiter.acquire(5));
        System.out.println(limiter.acquire(5));
        System.out.println(limiter.acquire(5));
        System.out.println(limiter.acquire(5));

        /**
         * 0.0
         * 9.999038
         * 0.998212
         * 0.999364
         * 0.99935
         *
         * 程序运行结果解析：
         * 第一次获取 ， 因为创建的时候会向桶内放一个令牌 ， 但是第一次要获取50个令牌 ， 那么就需要按照限定的规则
         * 1秒5个 ， 就造成了第二次的获取5个令牌时间是在10秒左右
         *
         * RateLimiter使用令牌桶算法，会进行令牌的累积，如果获取令牌的频率比较低，则不会导致等待，直接获取令牌。
         * RateLimiter由于会累积令牌，所以可以应对突发流量。也就是说如果同时请求5个令牌，由于此时令牌桶中有累积的令牌，能
         * 够快速响应请求。
         * RateLimiter在没有足够的令牌发放时，采用的是滞后的方式进行处理，也就是前一个请求获取令牌所需要等待的时间由下一次
         * 请求来承受和弥补，也就是代替前一个请求进行等待
         *
         */
    }

}